/*
 * Copyright (c) 2020, HiHope Community.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice, this
 *    list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 *    this list of conditions and the following disclaimer in the documentation
 *    and/or other materials provided with the distribution.
 *
 * 3. Neither the name of the copyright holder nor the names of its
 *    contributors may be used to endorse or promote products derived from
 *    this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include <stdio.h>
#include <unistd.h>
#include <string.h>

#include "ohos_init.h"
#include "cmsis_os2.h"
#include "wifiiot_gpio.h"
#include "wifiiot_gpio_ex.h"
#include "wifiiot_watchdog.h"

#include "ui_core.h"
#include "ui_test.h"

typedef enum {
    ITEM_TEST1 = 1,
    ITEM_TEST2,

    ITEM_MAX
} ItemId;

struct MainUiContext
{
    int mainLed1;
    int selected;
    int drawCount;

    UI* uiEntries[ITEM_MAX];
};
typedef struct MainUiContext MainUiContext;

static void MainUiEnter(UI* ui)
{
    printf("================================\r\n");
    LOGI("%p %s", ui, ui->name);
    if (ui->ctx == NULL) return;
    MainUiContext* mainCtx = (MainUiContext*) ui->ctx;

    printf("1. press main board key to control main board LED1!\r\n");
    printf("2. press OLED board LEFT key to swtich next UI to entering!\r\n");
    printf("3. press OLED board RIGHT key to enter a selected UI!\r\n");
    printf("Following UI can be selected:\r\n");
    for (int i = 1; i < ITEM_MAX; i++) {
        printf("  %d. name = %s\r\n", (i+1), mainCtx->uiEntries[i]->name);
    }

    mainCtx->drawCount = 0;
}

static void MainUiLeave(UI* ui)
{
    LOGI("%p %s", ui, ui->name);
    printf("================================\r\n");
}

static void MainUiOnKey(UI* ui, KeyEvent event)
{
    LOGI("%p %s", ui, ui->name);
    if (ui->ctx == NULL) return;
    MainUiContext* mainCtx = (MainUiContext*) ui->ctx;
    UI* targetUi = NULL;

    if (event.type == KEY_RELEASED) return;

    switch (event.key)
    {
    case K_USER:
        mainCtx->mainLed1 = !mainCtx->mainLed1;
        GpioSetOutputVal(WIFI_IOT_IO_NAME_GPIO_9, mainCtx->mainLed1);
        LOGI("switch LED1 state");
        break;
    case K_LEFT:
        mainCtx->selected++;
        if (mainCtx->selected == ITEM_MAX) {
            mainCtx->selected = ITEM_TEST1;
        }
        targetUi = mainCtx->uiEntries[mainCtx->selected];
        LOGI("update selected ui %d: %s", mainCtx->selected, targetUi->name);
        break;
    case K_RIGHT:
        targetUi = mainCtx->uiEntries[mainCtx->selected];
        LOGI("prepare to enter ui %d: %s", mainCtx->selected, targetUi->name);
        UISwitch(mainCtx->uiEntries[mainCtx->selected]);
        break;
    default:
        break;
    }
}

static void MainUiDraw(UI* ui)
{
    if (ui->ctx == NULL) return;
    MainUiContext* mainCtx = (MainUiContext*) ui->ctx;

    mainCtx->drawCount++;
    if (mainCtx->drawCount == 1) {
        LOGI("first frame draw of %s", ui->name);
    }
}

static void MainUiContextAddUI(MainUiContext* ctx, ItemId id, UI* ui)
{
    if (ctx == NULL || ((unsigned)id) > ITEM_MAX) return;
    ctx->uiEntries[id] = ui;
}

static void MainUiInit(UI* ui)
{
    if (ui == NULL) return;

    LOGI("%p %s", ui, ui->name);

    MainUiContext* ctx = ui->ctx;
    memset(ctx, 0, sizeof(MainUiContext));

    MainUiContextAddUI(ctx, ITEM_TEST1, TestUiNew("test1"));
    MainUiContextAddUI(ctx, ITEM_TEST2, TestUiNew("TEST2"));

    // main board LED1 pin
    IoSetFunc(WIFI_IOT_IO_NAME_GPIO_9, WIFI_IOT_IO_FUNC_GPIO_9_GPIO);
    GpioSetDir(WIFI_IOT_IO_NAME_GPIO_9, WIFI_IOT_GPIO_DIR_OUT);
}

static void MainUiDeinit(UI* ui)
{
    if (ui == NULL) return;

    LOGI("%p %s", ui, ui->name);

    MainUiContext* ctx = ui->ctx;
    for (int i = 0; i < ITEM_MAX; i++) {
        UIDestroy(ctx->uiEntries[i]);
    }
}

static void RunMainUI(void)
{
    LOGI("RunMainUI start....");

    MainUiContext mainCtx = {0};
    UI* mainUI = UICreate(&mainCtx, "Main", MainUiDraw, MainUiEnter, MainUiLeave, MainUiOnKey, MainUiInit, MainUiDeinit);

    UIRun(mainUI);

    UIDestroy(mainUI);
}

static void MainUiTask(void* arg)
{
    (void) arg;

    osDelay(20);

    GpioInit();
    WatchDogDisable();

    RunMainUI();
}

static void StartMainUI(void)
{
    osThreadAttr_t attr;
    attr.name = "UITask";
    attr.attr_bits = 0U;
    attr.cb_mem = NULL;
    attr.cb_size = 0U;
    attr.stack_mem = NULL;
    attr.stack_size = 10240;
    attr.priority = osPriorityNormal;
    if (osThreadNew(MainUiTask, NULL, &attr) == NULL) {
        printf("[StartMainUI] Falied to create task for RunMainUI!\n");
    }
}

SYS_RUN(StartMainUI);
